﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration;
using IrendilDLL.Database;
using System.Data;
using IrendilDLL;
using System.Data.SqlClient;
using System.IO;
using IrendilDLL.utilities;
using System.Management;
using System.Net.NetworkInformation;

namespace IrendilDLL.PageControls
{
    public class MonitorSPControl
    {
        /// <summary>
        /// Costruttore di default
        /// </summary>
        public MonitorSPControl()
        {
            // Procedo solo se é correttamente inizializzata la variabile di sessione
            installationGUID = (String)HttpContext.Current.Session["installationGUID"];

            // Ottengo la stringa di connessione al db
            localSqlServerStr = ConfigurationManager.ConnectionStrings["LocalSqlServer"].ConnectionString;
        }

        /// <summary>
        /// Guid installazione di riferimento
        /// </summary>
        String installationGUID = null;
        /// <summary>
        /// Stringa di connessione al db
        /// </summary>
        string localSqlServerStr = null;
        /// <summary>
        /// Riferimento al file di log
        /// </summary>
        TextWriter logFile;
        /// <summary>
        /// Soglia di warning
        /// </summary>
        private float warningThreshold = 10;
        /// <summary>
        /// Soglia di alert
        /// </summary>
        private float alertThreshold = 5;

        /// <summary>
        /// properties di WarningThreshold
        /// </summary>
        public float WarningThreshold
        {
            get { return warningThreshold; }
            set { warningThreshold = value; }
        }
        /// <summary>
        /// properties di alertThreshold
        /// </summary>
        public float AlertThreshold
        {
            get { return alertThreshold; }
            set { alertThreshold = value; }
        }

        /// <summary>
        /// Metodo che preleva da DB gli eventi e li visualizza opportunamente
        /// </summary>
        public DataTable getStoreLogDT(String spSelected, DateTime fromDate, DateTime toDate)
        {
            // Prelevo i dati da DB
            try
            {
                DataBaseManager dbManager = new DataBaseManager(localSqlServerStr);

                // Imposto i parametri per la QUERY
                SqlParameter[] parameters = new SqlParameter[3];

                //// Nel caso non sia selezionato nulla non filtro altrimenti...
                //if (hostSelected == null || hostSelected == "")
                //    parameters[0] = new SqlParameter("@GUIDHost", "%");
                //else
                //    parameters[0] = new SqlParameter("@GUIDHost", hostSelected.ToString().ToUpper());
                // Le date devono essere sempre impostate
                spSelected = "%" + spSelected + "%";
                parameters[0] = new SqlParameter("@spSelected", spSelected);
                parameters[1] = new SqlParameter("@fromDate", fromDate);
                parameters[2] = new SqlParameter("@toDate", toDate);

                // Apro la transazione, eseguo la store e la chiudo
                dbManager.OpenTransaction();
                DataSet eventDs = dbManager.EseguiStored("sp_getProcedureLog", parameters);
                dbManager.CloseTransaction();

                // Se la query torna dati continuo
                if (eventDs != null && eventDs.Tables.Count > 0)
                {
                    // Prelevo il dataTable con i dati
                    DataTable dt = eventDs.Tables[0];

                    return dt;
                }
                else
                    return null;
            }
            catch (Exception ex)
            {
                // Istanzio la classe di gestione dell'errore
                LogErrors logError = new LogErrors();
                // Scrivo l'errore su file
                logError.WriteLogToFile(ex.Source+": "+ex.Message);
                // Rimbalzo l'eccezione per la visualizzazione su gui
                throw ex;
            }

        }

        /// <summary>
        /// Metodo che esegue la store procedure passata per l'host indicato
        /// </summary>
        /// <param name="storeSelected">Store da eseguire</param>
        /// <param name="hostSelected">Host selezionato</param>
        public void executeImportSP(String storeSelected, String hostSelected)
        {

            try
            {
                DataBaseManager dbManager = new DataBaseManager(localSqlServerStr);

                // Imposto i parametri per la QUERY
                SqlParameter[] parameters = new SqlParameter[2];

                // Passo il guid dell'installazione
                parameters[0] = new SqlParameter("@GUID_Installation", installationGUID);
                // Se é stato selezionato l'host lo imposto
                if (hostSelected != "" && hostSelected != null)
                {
                    Guid hostGuid = new Guid(hostSelected);
                    parameters[1] = new SqlParameter("@GUID_Host", hostGuid);
                }
                else
                    parameters[1] = new SqlParameter("@GUID_Host", DBNull.Value);
                

                // Apro la transazione, eseguo la store e la chiudo
                //dbManager.OpenTransaction();
                dbManager.EseguiStoredVoid(storeSelected, parameters);
                //dbManager.CloseTransaction();

            }
            catch (Exception ex)
            {
                // Istanzio la classe di gestione dell'errore
                LogErrors logError = new LogErrors();
                // Scrivo l'errore su file
                logError.WriteLogToFile(ex.Source+": "+ex.Message);
                // Rimbalzo l'eccezione per la visualizzazione su gui
                throw ex;
            }
        }


        /// Metodo che torna un datatable contenente i risultati del test dei dischi da presentare a monitor
        /// </summary>
        /// <returns></returns>
        public void executeImportDiskWMI()
        {
            // Istanzio la classe di appoggio per il db
            IrendilDbManager irendilDbManager = new IrendilDbManager(localSqlServerStr);
            DataSet hostDs = irendilDbManager.getHostsList(installationGUID);

            // Se la query torna dati continuo
            if (hostDs != null && hostDs.Tables.Count > 0)
            {
                // Ottengo il DataTable
                DataTable hostDt = hostDs.Tables[0];

                // Ciclo su tutte le righe del dt (hosts)
                for (int i = 0; i < hostDt.Rows.Count; i++)
                {

                    // Eseguo la query object
                    ManagementObjectSearcher searcherMngObj = null;
                    ManagementObjectCollection queryObjectCollection = null;
                    // Eseguo la query sql
                    ManagementObjectSearcher searcherMngObjSelect = null;
                    ManagementObjectCollection querySelectCollection = null;

                    try
                    {
                        // oggetto contenente tutte le possibili impostazioni di connessione
                        ConnectionOptions connectionOptions = new ConnectionOptions();
                        //connectionOptions.Impersonation = ImpersonationLevel.Impersonate;
                        connectionOptions.Authentication = AuthenticationLevel.Default;
                        //connectionOptions.Timeout = new TimeSpan(0, 0, 30);
                        //connectionOptions.EnablePrivileges = true;
                        connectionOptions.Username = hostDt.Rows[i]["WinUsername"].ToString();
                        connectionOptions.Password = hostDt.Rows[i]["WinPassword"].ToString();
                        connectionOptions.Timeout = new TimeSpan(0, 0, 1);

                        // Dichiaro la variabile che gestirà il ping
                        Ping ping = new Ping();
                        // Eseguo il ping per verificare che il server sia raggiungibile
                        PingReply sys_pingreply = ping.Send(hostDt.Rows[i]["PrimaryIp"].ToString(), 500);
                        // Controllo lo stato della risposta
                        if (sys_pingreply.Status == IPStatus.Success)
                        {
                            //connectionOptions.Username = "USL3\\ebitaet";
                            //connectionOptions.Password = "ebitaetservice"; 
                            // Imposta lo scope/spazio dei nomi/dominio/indirizzo e i paramentri di conn
                            //ManagementScope managementScope = new ManagementScope("\\\\127.0.0.1\\root\\cimv2", connectionOptions);
                            ManagementScope managementScope = new ManagementScope("\\\\" + hostDt.Rows[i]["PrimaryIp"].ToString() + "\\root\\cimv2", connectionOptions);
                            // Effettuo la connessione
                            managementScope.Connect();
                            // Preparo una object query per determinarmi le info sul S.O.
                            ObjectQuery queryObject = new ObjectQuery("SELECT * FROM Win32_OperatingSystem");
                            // Preparo una query SQL per ricavarmi tutti i dischi e le loro proprietà
                            SelectQuery querySelect = new SelectQuery("SELECT * from Win32_Volume");

                            // Eseguo la query object
                            searcherMngObj = new ManagementObjectSearcher(managementScope, queryObject);
                            queryObjectCollection = searcherMngObj.Get();
                            // Eseguo la query sql
                            searcherMngObjSelect = new ManagementObjectSearcher(managementScope, querySelect);
                            querySelectCollection = searcherMngObjSelect.Get();
                        }
                        else
                        {
                            // Imposto a null gli oggetti che dovevano contenere i dati sui dischi/S.O.
                            searcherMngObjSelect = null;
                            querySelectCollection = null;
                        }


                    }
                    catch (Exception ex)
                    {
                        // Imposto a null gli oggetti che dovevano contenere i dati sui dischi/S.O.
                        searcherMngObjSelect = null;
                        querySelectCollection = null;
                    }

                    // Controllo che siano valorizzati i dati prelevati da remoto
                    if (queryObjectCollection != null && querySelectCollection != null
                        && querySelectCollection.Count > 0 && queryObjectCollection.Count == 1)
                    {

                        

                        // Istanzio l'oggetto di calcolo statistico sui dischi
                        DisksStatistic diskStatistic = new DisksStatistic();

                        // Ciclo sio dischi
                        foreach (ManagementObject managementObj in queryObjectCollection)
                        {

                            // Uso il foreach per mia comodità (ICollection ecc...) ma intanto gli elementi contenuti sono sempre
                            // 1 (c'é il controllo apposito)
                            foreach (ManagementObject managementObjDisk in querySelectCollection)
                            {
                                // Controllo prima che non ci siano dischi "virtuali" cdrom con size nullo

                                if (managementObjDisk["Capacity"] != null)
                                {
                                    if (Convert.ToDouble(managementObjDisk["Capacity"]) > 0.01)
                                    {
                                        // Calcolo lo spazio libero
                                        float freeSpacePerc = Convert.ToSingle(managementObjDisk["FreeSpace"]) * 100 / Convert.ToSingle(managementObjDisk["Capacity"]);

                                        int remainingDays = diskStatistic.calculateRemainingDays(new Guid((hostDt.Rows[i]["GUID"]).ToString()),
                                            Convert.ToString(managementObjDisk["Name"]),
                                            Convert.ToDouble(managementObjDisk["Capacity"]),
                                            Convert.ToDouble(managementObjDisk["FreeSpace"]));

                                        String status = "";
                                        // Imposto due soglie di monitoraggio
                                        // Se é presente la stima, imposto l'errore solo se i giorni rimanenti non sono tendenti ad infinito (ad es i dischi chiusi)
                                        if (remainingDays != -1 && remainingDays > 0)
                                        {
                                            // Per mettere OK deve esserci una certa percentuale e almeno 30 giorni di stima
                                            if (freeSpacePerc > warningThreshold || remainingDays > 120)
                                                status = " OK ";
                                            if (freeSpacePerc <= warningThreshold && freeSpacePerc > alertThreshold && remainingDays < 5000)
                                                status = " WARNING ";
                                            if (freeSpacePerc <= alertThreshold && remainingDays < 5000)
                                                status = " ALERT ";
                                        }
                                        else
                                        {
                                            if (freeSpacePerc > warningThreshold)
                                                status = " OK ";
                                            if (freeSpacePerc <= warningThreshold && freeSpacePerc > alertThreshold)
                                                status = " WARNING ";
                                            if (freeSpacePerc <= alertThreshold)
                                                status = " ALERT ";
                                        }

                                        // Eseguo la store salva il record su DB
                                        SqlParameter[] parameters = new SqlParameter[10];
                                        parameters[0] = new SqlParameter("@GUIDHost", hostDt.Rows[i]["GUID"]);
                                        parameters[1] = new SqlParameter("@OperatingSystem", managementObj["Caption"]);
                                        parameters[2] = new SqlParameter("@Volume", managementObjDisk["Name"]);
                                        parameters[3] = new SqlParameter("@VolumeName", managementObjDisk["Label"]);
                                        parameters[4] = new SqlParameter("@Size", Convert.ToSingle(managementObjDisk["Capacity"]));
                                        parameters[5] = new SqlParameter("@FreeSpace", Convert.ToSingle(managementObjDisk["FreeSpace"]));
                                        parameters[6] = new SqlParameter("@FreeSpacePerc", freeSpacePerc);
                                        parameters[7] = new SqlParameter("@Status", status);
                                        parameters[8] = new SqlParameter("@DateTime", DateTime.Now);
                                        // Controllo che la stima sia stata calcolata correttamente prima di scriverla su db
                                        if (remainingDays == -1)
                                            parameters[9] = new SqlParameter("@RemainingDays", DBNull.Value);
                                        else
                                            parameters[9] = new SqlParameter("@RemainingDays", remainingDays);

                                        // Istanzio l'oggetto per la connessione al db
                                        DataBaseManager dbManager = new DataBaseManager(localSqlServerStr);
                                        // Apro la connessione al db
                                        dbManager.OpenTransaction();

                                        dbManager.EseguiStoredVoid("sp_InsertDisk", parameters);

                                        dbManager.CloseTransaction();
                                    }
                                }
                            }
                        }


                    }
                    else
                    {
                        // Istanzio l'oggetto per la connessione al db
                        DataBaseManager dbManager = new DataBaseManager(localSqlServerStr);

                        // Eseguo la store salva il record su DB
                        SqlParameter[] parameters = new SqlParameter[10];
                        parameters[0] = new SqlParameter("@GUIDHost", hostDt.Rows[i]["GUID"]);
                        parameters[1] = new SqlParameter("@OperatingSystem", "Host non raggiungibile");
                        parameters[2] = new SqlParameter("@Volume", "Unknown");
                        parameters[3] = new SqlParameter("@VolumeName", "Host non raggiungibile");
                        float zeroFloat = 0;
                        parameters[4] = new SqlParameter("@Size", zeroFloat);
                        parameters[5] = new SqlParameter("@FreeSpace", zeroFloat);
                        parameters[6] = new SqlParameter("@FreeSpacePerc", zeroFloat);
                        parameters[7] = new SqlParameter("@Status", " UNKNOWN ");
                        parameters[8] = new SqlParameter("@DateTime", DateTime.Now);
                        parameters[9] = new SqlParameter("@RemainingDays", DBNull.Value);

                        // Apro la connessione al db
                        dbManager.OpenTransaction();
                        dbManager.EseguiStoredVoid("sp_InsertDisk", parameters);
                        dbManager.CloseTransaction();
                        
                    }

                }

                // Istanzio l'oggetto per la connessione al db
                DataBaseManager dbManagerError = new DataBaseManager(localSqlServerStr);
                // Apro la connessione al db
                dbManagerError.OpenTransaction();

                // Scrivo su DB il log della procedura di import
                SqlParameter[] parametersLog = new SqlParameter[4];
                parametersLog[0] = new SqlParameter("@ProcedureName", "sp_importDisks");
                parametersLog[1] = new SqlParameter("@ErrorLine", DBNull.Value);
                parametersLog[2] = new SqlParameter("@ErrorMessage", DBNull.Value);
                parametersLog[3] = new SqlParameter("@AdditionalInfo", "Import applicativo (non SP)");
                dbManagerError.EseguiStoredVoid("sp_TransactionLog", parametersLog);

                dbManagerError.CloseTransaction();

            }



        }
    }
}
